package com.engine4cloud.tdf.supervision.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.engine4cloud.tdf.admin.api.dto.UserRoleResultDTO;
import com.engine4cloud.tdf.admin.api.feign.RemoteUserRoleService;
import com.engine4cloud.tdf.common.core.constant.SecurityConstants;
import com.engine4cloud.tdf.common.core.constant.SupervisionBusinessConstants;
import com.engine4cloud.tdf.common.core.constant.enums.InvAuditActionStatusEnum;
import com.engine4cloud.tdf.common.core.constant.enums.InvAuditResultStatusEnum;
import com.engine4cloud.tdf.common.core.constant.enums.YesNoEnum;
import com.engine4cloud.tdf.common.core.exception.ValidateCodeException;
import com.engine4cloud.tdf.common.core.util.R;
import com.engine4cloud.tdf.common.core.util.RetOps;
import com.engine4cloud.tdf.common.core.util.lambda.Actions;
import com.engine4cloud.tdf.common.data.web.query.Pages;
import com.engine4cloud.tdf.common.data.web.query.Queries;
import com.engine4cloud.tdf.common.data.web.response.PageInfo;
import com.engine4cloud.tdf.common.data.web.response.Params;
import com.engine4cloud.tdf.common.security.service.TdfUser;
import com.engine4cloud.tdf.common.security.util.SecurityUtils;
import com.engine4cloud.tdf.supervision.component.CallBackComponent;
import com.engine4cloud.tdf.supervision.convert.DcpgAuditResultConvert;
import com.engine4cloud.tdf.supervision.convert.DcpgInvestigationConvert;
import com.engine4cloud.tdf.supervision.convert.JzdxConvert;
import com.engine4cloud.tdf.supervision.convert.JzdxJudgmentConvert;
import com.engine4cloud.tdf.supervision.dto.create.*;
import com.engine4cloud.tdf.supervision.dto.InvAuditDTO;
import com.engine4cloud.tdf.supervision.dto.query.DcpgAuditQueryDTO;
import com.engine4cloud.tdf.supervision.dto.query.DcpgInvCrimeNameQueryDTO;
import com.engine4cloud.tdf.supervision.dto.result.DcpgAuditResultDTO;
import com.engine4cloud.tdf.supervision.dto.result.DcpgInvCrimeNameResultDTO;
import com.engine4cloud.tdf.supervision.dto.result.DcpgInvestigationResultDTO;
import com.engine4cloud.tdf.supervision.dto.result.EnumsTypeResultDTO;
import com.engine4cloud.tdf.supervision.dto.update.DcpgPreActionUpdateDTO;
import com.engine4cloud.tdf.supervision.entity.DcpgAuditResultEntity;
import com.engine4cloud.tdf.supervision.mapper.DcpgAuditResultMapper;
import com.engine4cloud.tdf.supervision.service.*;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 调查评估审核-审核
 *
 * @author wenjie
 * @date 2024-02-29 11:13:01
 */
@Service
public class DcpgAuditResultServiceImpl extends ServiceImpl<DcpgAuditResultMapper, DcpgAuditResultEntity> implements DcpgAuditResultService {

    @Lazy
    @Resource
    private DcpgInvestigationService investigationService;

    @Lazy
    @Resource
    private DcpgInvCrimeNameService crimeNameService;

    @Resource
    private JzdxService jzdxService;

    @Resource
    private JzdxJudgmentService judgmentService;

    @Resource
    private RemoteUserRoleService userRoleService;

    @Resource
    private CallBackComponent callBackComponent;

    @Override
    public PageInfo<DcpgAuditResultDTO> pageList(Params pageable, DcpgAuditQueryDTO dto) {
        Page<DcpgAuditResultEntity> page = page(Pages.page(pageable), wrapper(dto));
        return Pages.convert(page, DcpgAuditResultConvert.INSTANCE::convert);
    }

    @Override
    public DcpgAuditResultDTO getById(Long id) {
        return DcpgAuditResultConvert.INSTANCE.convert(super.getById(id));
    }

    /**
     * @param dto   入参
     * @param audit 审核参数
     * @return Boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean audit(DcpgAuditCreateDTO dto, InvAuditDTO audit) {
        investigationService.changeAction(new DcpgPreActionUpdateDTO(dto.getDcpgbh(), audit.getStatus()));
        return super.save(DcpgAuditResultConvert.INSTANCE.create(dto, audit, SecurityUtils.getUser()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean assign(DcpgAuditAssignCreateDTO dto) {
        TdfUser user = SecurityUtils.getUser();
        this.audit(dto, new InvAuditDTO(user.getDeptId(), InvAuditActionStatusEnum.COUNTRY_ASSIGN));
        return investigationService.changeDepart(DcpgAuditResultConvert.INSTANCE.update(dto.getDcpgbh(), dto.getJsbm()), InvAuditActionStatusEnum.COUNTRY_ASSIGN);
    }

    /**
     * 所接收、所拒绝、所提交、县通过、县拒绝后，调查评估的数据不设置所属部门的原因是：需要让所里的人看到这条结果
     *
     * @param dto DcpgAuditCreateDTO
     * @return Boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean accept(DcpgAuditCreateDTO dto) {
        DcpgAuditResultDTO audit = Optional.ofNullable(this.getLatest(dto.getDcpgbh(), InvAuditActionStatusEnum.COUNTRY_ASSIGN))
                .orElseThrow(() -> new ValidateCodeException("前置流程：" + InvAuditActionStatusEnum.COUNTRY_ASSIGN.getDesc() + "未找到，请确认后再操作"));

        TdfUser user = SecurityUtils.getUser();
        return this.audit(dto, new InvAuditDTO(user.getDeptId(), InvAuditActionStatusEnum.VILLAGE_ACCEPT));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean refuse(DcpgAuditCreateDTO dto) {
        TdfUser user = SecurityUtils.getUser();
        DcpgAuditResultDTO audit = Optional.ofNullable(this.getLatest(dto.getDcpgbh(), InvAuditActionStatusEnum.COUNTRY_ASSIGN))
                .orElseThrow(() -> new ValidateCodeException("前置流程：" + InvAuditActionStatusEnum.COUNTRY_ASSIGN.getDesc() + "未找到，请确认后再操作"));
        this.audit(dto, new InvAuditDTO(user.getDeptId(), InvAuditActionStatusEnum.VILLAGE_REFUSE));
        //换部门
        return investigationService.changeDepart(DcpgAuditResultConvert.INSTANCE.update(dto.getDcpgbh(), audit.getPreDeptId()), InvAuditActionStatusEnum.VILLAGE_REFUSE);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean submit(DcpgAuditCreateDTO dto) {
        DcpgAuditResultDTO audit = Optional.ofNullable(this.getLatest(dto.getDcpgbh(), InvAuditActionStatusEnum.VILLAGE_ACCEPT))
                .orElseThrow(() -> new ValidateCodeException("前置流程：" + InvAuditActionStatusEnum.VILLAGE_ACCEPT.getDesc() + "未找到，请确认后再操作"));
        this.audit(dto, new InvAuditDTO(audit.getPreDeptId(), InvAuditActionStatusEnum.VILLAGE_SUBMIT));
        //换部门
        return investigationService.changeDepart(DcpgAuditResultConvert.INSTANCE.update(dto.getDcpgbh(), audit.getPreDeptId()), InvAuditActionStatusEnum.VILLAGE_REFUSE);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean audit(DcpgCountyAuditCreateDTO dto) {
        TdfUser user = SecurityUtils.getUser();
        DcpgInvestigationResultDTO investigationResult = Optional.ofNullable(investigationService.getByCode(dto.getDcpgbh()))
                .orElseThrow(() -> new ValidateCodeException("调查评估数据不存在"));

        //保存调查评估结果
        investigationService.saveOrUpdate(DcpgInvestigationConvert.INSTANCE.convert(investigationResult, dto));

        DcpgAuditResultDTO audit = Optional.ofNullable(this.getLatest(dto.getDcpgbh(), InvAuditActionStatusEnum.VILLAGE_SUBMIT))
                .orElseThrow(() -> new ValidateCodeException("前置流程：" + InvAuditActionStatusEnum.VILLAGE_SUBMIT.getDesc() + "未找到，请确认后再操作"));
        //审核通过或拒绝
        this.audit(dto, new InvAuditDTO(user.getDeptId(), InvAuditActionStatusEnum.valueOf(dto.getDcshjg().getType())));
        //移交矫正对象
        if (Objects.equals(InvAuditResultStatusEnum.COUNTRY_APPROVE, dto.getDcshjg()) && Objects.equals(YesNoEnum.YES.getCode(), dto.getDcpgjg())) {
            callBackComponent.execute(() -> {
                investigationResult.setNsyjzlb(dto.getNsyjzlb());
                this.delivery(investigationResult);
                //已入矫设定
                this.audit(dto, new InvAuditDTO(user.getDeptId(), InvAuditActionStatusEnum.DELIVERY));
            });
        }

        return true;
    }

    @Override
    public List<DcpgAuditResultDTO> getListByCode(String code) {
        return super.list(wrapper(new DcpgAuditQueryDTO(code))).stream().map(DcpgAuditResultConvert.INSTANCE::convert).filter(f -> !Objects.equals(InvAuditActionStatusEnum.DELIVERY.getType(), f.getShjg())).toList();
    }

    @Override
    public void delivery(DcpgInvestigationResultDTO inv) {

        DcpgInvCrimeNameQueryDTO crimeNameQuery = new DcpgInvCrimeNameQueryDTO(inv.getDcpgbh());
        List<DcpgInvCrimeNameResultDTO> crimeList = crimeNameService.findList(crimeNameQuery);
        Actions.apply(CollectionUtils.isNotEmpty(crimeList), () -> inv.setCrimeNameList(crimeList));

        JzdxCreateDTO corrector = JzdxConvert.INSTANCE.create(inv);
        String code = jzdxService.create(corrector);

        JzdxJudgmentCreateDTO judgment = JzdxJudgmentConvert.INSTANCE.create(inv, code);
        judgmentService.create(judgment);
    }

    @Override
    public DcpgAuditResultDTO getLatest(String code, InvAuditActionStatusEnum status) {
        return this.baseMapper.findLatest(code, status.getType());
    }

    @Override
    public List<EnumsTypeResultDTO> status() {
        List<EnumsTypeResultDTO> labelList = new ArrayList<>(Arrays.stream(InvAuditActionStatusEnum.values())
                .map(state -> new EnumsTypeResultDTO(state.getType(), state.getStatus()))
                .toList());

        //特殊需求：根据角色过滤
        R<List<UserRoleResultDTO>> remoteUserRoleList = userRoleService.roleListByUserId(SecurityUtils.getUser().getId(), SecurityConstants.FROM_IN);
        List<UserRoleResultDTO> userRoleList = RetOps.of(remoteUserRoleList).getData().filter(CollectionUtils::isNotEmpty)
                .orElseThrow(() -> new ValidateCodeException("没有数据权限!"));

        List<String> roleCodeList = userRoleList.stream().map(UserRoleResultDTO::getRoleCode).toList();
        if (roleCodeList.contains(SupervisionBusinessConstants.SFS_USER_ROLE)) {
            labelList.removeIf(l -> Objects.equals(InvAuditActionStatusEnum.CREATE.getType(), l.getValue())
                    || Objects.equals(InvAuditActionStatusEnum.VILLAGE_SUBMIT.getType(), l.getValue())
                    || Objects.equals(InvAuditActionStatusEnum.COUNTRY_APPROVE.getType(), l.getValue())
                    || Objects.equals(InvAuditActionStatusEnum.COUNTRY_REJECT.getType(), l.getValue())
                    || Objects.equals(InvAuditActionStatusEnum.DELIVERY.getType(), l.getValue()));
        }

        return labelList;
    }

    private LambdaQueryWrapper<DcpgAuditResultEntity> wrapper(DcpgAuditQueryDTO query) {
        LambdaQueryWrapper<DcpgAuditResultEntity> wrapper = Queries.lambda();
        Queries.accept(query.getId(), v -> wrapper.eq(DcpgAuditResultEntity::getId, v));
        Queries.accept(query.getDcpgbh(), v -> wrapper.eq(DcpgAuditResultEntity::getDcpgbh, v));
        Queries.accept(query.getPreDeptId(), v -> wrapper.eq(DcpgAuditResultEntity::getPreDeptId, v));
        wrapper.orderByAsc(DcpgAuditResultEntity::getCreateTime);
        return wrapper;
    }

}